<template>
  <dw-menu-group
    ref="menuGroupRef"
    v-model:active-form-data="activeFormData"
    v-model:form-data-map="formDataMap"
    :datagrid-menu-info="datagridInfo"
    :before-close="beforeMenuClose"
    @onAddFormMenu="onAddFormMenu"
    @handleSelect="handleSelect"
    @onSave="onSave"
    @onSaveAdd="onSaveAdd"
  >
    <template #formBtn>
      <slot name="formBtn"></slot>
    </template>
    <template #datagrid>
      <dw-search-form v-if="showSearchForm" ref="searchFormRef" :form-items="searchFormItems" @onSearch="onSearch">
        <template v-for="(item, index) in slotSearchItems" :key="index" #[`${item.slotName}`]="{ config, searchFormData }">
          <slot :name="item.slotName" :config="config" :form-data="searchFormData"></slot>
        </template>
      </dw-search-form>
      <dw-btn-toolbar v-if="showButton" :buttons="buttons">
        <template v-for="(button, index) in slotButtons" :key="index" #[`${button.slotName}`]="{ config }">
          <slot :name="button.slotName" :config="config"></slot>
        </template>
      </dw-btn-toolbar>

      <div class="dw-data-warpper">
        <dw-datagrid
          ref="tableRef"
          :init-loaded="initLoaded"
          :is-tree="isTree"
          :columns="columns"
          :operation-width="operationWidth"
          :checkbox="checkbox"
          :get-page-http-config="getPageHttpConfig"
          :show-operation="showOperation"
          :operation-items="operationItems"
          @on-row-dblclick="rowDblClick"
        >
          <template v-for="(column, index) in slotColumns" :key="index" #[`${column.slotName}`]="{ scope }">
            <slot :name="column.slotName" :scope="scope"></slot>
          </template>
          <template v-for="(oprationItem, index) in operationItems" :key="index" #[`${oprationItem.slotName}`]="{ scope }">
            <slot :name="oprationItem.slotName" :scope="scope"></slot>
          </template>
        </dw-datagrid>
      </div>
    </template>
    <template #menuGroupform="{ activeId, formMenuList }">
      <div v-for="(item, index) in formMenuList" :key="index" v-show="activeId === item.id" style="height: 100%">
        <dw-menu-group-form
          ref="menuGroupFormRef"
          :active-id="item.id"
          :init-form-data="initFormData"
          v-model:active-form-data="activeFormData"
          v-model:form-data-map="formDataMap"
          :state="item.state?.value"
          :menu-item="item"
          :before-save="beforeSave"
          :after-success-save="afterSuccessSave"
          :get-info-http-config="getInfoHttpConfig"
          :update-info-http-config="updateInfoHttpConfig"
          :add-info-http-config="addInfoHttpConfig"
          :renderBindEditData="renderBindEditData"
        >
          <template #default="{ status }">
            <slot name="formSlot" :status="status" :activeId="activeId!"></slot>
          </template>
        </dw-menu-group-form>
      </div>
    </template>
  </dw-menu-group>
</template>
<script setup lang="ts" generic="T extends IMasterEntity">
import type { IMenuItem } from '@/types/menu-group';
import type {
  IColumn,
  IButton,
  FormItemConfig,
  IInputConfig,
  IOperationItem,
  IDelInfoHttpConfig,
  IGetPageHttpConfig,
  IUpdateInfoHttpConfig,
  IAddInfoHttpConfig,
  IGetInfoHttpConfig,
  IDelListHttpConfig,
} from '@/types/menu-datagrid-form';
import { nanoid } from 'nanoid';
import { h, markRaw, ref, type PropType } from 'vue';
import DwMenuGroup from './menu-group/index.vue';
import DwSearchForm from './search-form/index.vue';
import DwBtnToolbar from './btn-toolbar/index.vue';
import DwDatagrid from './datagrid/index.vue';
import DwMenuGroupForm from './menu-group-form/index.vue';
import { dwHttp } from '@/utils/http';
import type { IMasterEntity } from '@/types/entity';
import { ElMessage, ElMessageBox } from 'element-plus';
import { QuestionFilled } from '@element-plus/icons-vue';
import { dwDeepClone, getIdArrayFormJsonList, template } from '@/utils/func';
defineOptions({
  name: 'DwMenuDatagridForm',
});

const props = defineProps({
  dataGridTitle: {
    type: String,
    required: true,
  },
  renderFormTitle: {
    type: Function as PropType<(stateValue: 'edit' | 'add', data?: T) => string>,
    required: true,
  },
  isTree: {
    type: Boolean,
    default: false,
  },
  renderBindEditData: null,
  showSearchForm: {
    type: Boolean,
    default: true,
  },
  operationWidth: {
    type: Number,
    default: 150,
  },
  beforeSave: {
    type: Function as PropType<(data: T, add?: boolean) => T | undefined>,
  },
  searchFormItems: {
    type: Array as PropType<FormItemConfig[]>,
    default: () => {
      const keywordItem: IInputConfig = {
        label: '关键字',
        code: 'keyword',
        width: 260,
        componentType: 'input',
        placeholder: '请输入关键字或者拼音首字母进行搜索',
        defaultValue: '',
      };
      return [keywordItem];
    },
  },
  showButton: {
    type: Boolean,
    default: true,
  },
  buttons: {
    type: Array as PropType<IButton[]>,
  },
  //初始化加载数据
  initLoaded: {
    type: Boolean,
    default: true,
  },
  getPageHttpConfig: {
    type: Object as PropType<IGetPageHttpConfig<T>>,
    required: true,
  },
  delInfoHttpConfig: {
    type: Object as PropType<IDelInfoHttpConfig>,
  },
  delListHttpConfig: {
    type: Object as PropType<IDelListHttpConfig>,
  },
  getInfoHttpConfig: {
    type: Object as PropType<IGetInfoHttpConfig<T>>,
  },
  addInfoHttpConfig: {
    type: Object as PropType<IAddInfoHttpConfig<T>>,
  },
  updateInfoHttpConfig: {
    type: Object as PropType<IUpdateInfoHttpConfig<T>>,
  },
  checkbox: {
    type: Boolean,
    default: true,
  },
  columns: {
    type: Array as PropType<IColumn[]>,
    required: true,
  },
  showOperation: {
    type: Boolean,
    default: true,
  },
  operationItems: {
    type: Array as PropType<IOperationItem<T>[]>,
  },
});
const emits = defineEmits(['handleSelect']);
const menuGroupRef = ref();
const searchFormRef = ref();
const slotSearchItems = props.searchFormItems.filter((item) => !!item.slotName) || [];
const slotColumns = props.columns.filter((column) => !!column.slotName) || [];
const slotButtons = props.buttons?.filter((button) => !!button.slotName) || [];
const tableRef = ref();
const showSearchForm = props.showSearchForm;
const initLoaded = props.initLoaded;
const menuGroupFormRef = ref();

const showButton = props.showButton;
const showOperation = props.showOperation;
const buttons = ref(props.buttons || []);
const operationItems = ref(props.operationItems || []);
const delInfoHttpConfig = props.delInfoHttpConfig;
const delListHttpConfig = props.delListHttpConfig;
const getPageHttpConfig = ref(props.getPageHttpConfig);
const getInfoHttpConfig = props.getInfoHttpConfig;
const addInfoHttpConfig = props.addInfoHttpConfig;
const updateInfoHttpConfig = props.updateInfoHttpConfig;
const isTree = props.isTree;
const _query = props.getPageHttpConfig.query;
const query = () => {
  let params = {};
  if (_query) {
    params = _query() || {};
  }
  const searchFormData = searchFormRef.value.getFormData();
  return { ...params, ...searchFormData };
};
getPageHttpConfig.value.query = query;

//激活表单的数据
const activeFormData = defineModel<T>('activeFormData');
//表单初始化数据
const initFormData: T = dwDeepClone(activeFormData.value as unknown as Record<string, unknown>) as unknown as T;

//组件中多个表达的数据
const formDataMap = ref<Record<string, T>>({});

/**
 * 按钮处理
 */
const addButton: IButton = {
  text: '新增',
  type: 'primary',
  onClick: () => {
    const formTitle = props.renderFormTitle('add');
    const id: string = nanoid();
    const menuItemId = `menu-item-${id}`;
    const menuItem: IMenuItem = {
      id: `menu-item-${id}`,
      menuItemName: formTitle,
      state: { value: 'add', label: '【新增】', color: 'red' },
    };
    if (!formDataMap.value) {
      formDataMap.value = {};
    }
    menuGroupRef.value.addFormMenu(menuItem);
  },
};
const batchDeleteButton: IButton = {
  text: '批量删除',
  type: 'danger',
  onClick: () => {
    const rows: T[] = tableRef.value.getSelectionRows();
    const total: number = rows.length;
    if (total > 0) {
      const idList = getIdArrayFormJsonList(rows);
      ElMessageBox({
        title: '询问',
        message: h('p', null, [h('span', null, '确认删除选中的'), h('span', { style: 'color: red' }, `${total}条`), h('span', null, '记录信息')]),
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        showCancelButton: true,
        icon: markRaw(QuestionFilled),
        type: 'warning',
        beforeClose: (action: string, instance: unknown, done: () => void) => {
          if (action === 'confirm') {
            dwHttp({
              url: delListHttpConfig!.url,
              data: idList,
              method: 'delete',
            }).then((res) => {
              console.log(res);
              tableRef.value.loadData();
            });
          }
          done();
        },
      });
    } else {
      ElMessage({ message: '请选择要删除的行记录!', type: 'error', plain: true });
    }
  },
};
if (showButton) {
  if (buttons.value && buttons.value.length > 0) {
    for (let i = 0; i < buttons.value.length; i++) {
      const button = buttons.value[i];
      if (button.code === 'add' && button.extendFlag) {
        buttons.value[i] = { ...addButton, ...button };
      } else if (button.code === 'batchDelete' && button.extendFlag) {
        buttons.value[i] = { ...batchDeleteButton, ...button };
      }
    }
  } else {
    buttons.value.push(addButton);
    buttons.value.push(batchDeleteButton);
  }
}
const editOperation: IOperationItem<T> = {
  icon: 'Edit',
  text: '编辑',
  type: 'primary',
  onClick: (index: number, rowdata: T) => {
    const id: string = nanoid();
    const formTitle = props.renderFormTitle('edit', rowdata);
    const menuItem: IMenuItem = {
      id: `menu-item-${id}`,
      menuItemName: formTitle,
      state: { value: 'edit', label: '【编辑】', color: 'green' },
      dataId: rowdata.id,
    };
    menuGroupRef.value.addFormMenu(menuItem);
  },
};
const delOperation: IOperationItem<T> = {
  icon: 'Delete',
  text: '删除',
  type: 'danger',
  onClick: (index: number, rowdata: T) => {
    let delInfoMsgEmphasize = '';
    if (delInfoHttpConfig?.delInfoMsgEmphasize) {
      delInfoMsgEmphasize = template(`【${delInfoHttpConfig.delInfoMsgEmphasize}】`, rowdata as unknown as Record<string, string>);
    } else {
      delInfoMsgEmphasize = '当前';
    }
    ElMessageBox({
      title: '询问',
      message: h('p', null, [h('span', null, '确认删除'), h('span', { style: 'color: red' }, delInfoMsgEmphasize), h('span', null, '记录信息')]),
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      showCancelButton: true,
      icon: markRaw(QuestionFilled),
      type: 'warning',
      beforeClose: (action, instance, done) => {
        if (action === 'confirm') {
          const url = template(delInfoHttpConfig!.url!, rowdata as unknown as Record<string, string>);
          dwHttp({
            url: url,
            method: 'delete',
          }).then((res) => {
            console.log(res);
            tableRef.value.loadData();
          });
        }
        done();
      },
    });
  },
};
if (showButton) {
  if (operationItems.value && operationItems.value.length > 0) {
    for (let i = 0; i < operationItems.value.length; i++) {
      const oprationItem = operationItems.value[i];
      if (oprationItem.code === 'edit' && oprationItem.extendFlag) {
        operationItems.value[i] = { ...editOperation, ...oprationItem };
      } else if (oprationItem.code === 'delInfo' && oprationItem.extendFlag) {
        operationItems.value[i] = { ...delOperation, ...oprationItem };
      }
    }
  } else {
    operationItems.value.push(editOperation);
    operationItems.value.push(delOperation);
  }
}
const datagridInfo = ref<IMenuItem>({ id: 'list', menuItemName: props.dataGridTitle });
const beforeMenuClose = (data: IMenuItem) => {
  console.log(data);

  return true;
};
const onAddFormMenu = () => {
  addFormMenu();
};
const handleSelect = (newData: string, oldData: string[]) => {
  emits('handleSelect', newData, oldData);
};
const addFormMenu = () => {
  const id: string = nanoid();
  const menuItemId = `menu-item-${id}`;
  const formTitle = props.renderFormTitle('add');
  const menuItem: IMenuItem = {
    id: `menu-item-${id}`,
    menuItemName: formTitle,
    state: { value: 'add', label: '【新增】', color: 'red' },
  };
  menuGroupRef.value.addFormMenu(menuItem);
};
const onSearch = () => {
  tableRef.value?.loadData();
};
const onSave = () => {
  const index = menuGroupRef.value.getActiveFormIndex();
  menuGroupFormRef.value[index].onSave();
};
const onSaveAdd = () => {
  const index = menuGroupRef.value.getActiveFormIndex();
  menuGroupFormRef.value[index].onSave(true);
};
const beforeSave = (formData: T, add?: boolean): T | undefined => {
  if (typeof props.beforeSave === 'function') {
    return props.beforeSave(formData, add);
  }
  return formData;
};
const afterSuccessSave = (formData: T, add?: boolean) => {
  const formTitle = props.renderFormTitle('edit', formData);
  menuGroupRef.value.setEditState(formTitle);
  tableRef.value?.loadData();
  if (add) {
    const formTitle = props.renderFormTitle('add');
    menuGroupRef.value.setAddState(formTitle, (i: number) => {
      menuGroupFormRef.value[i].resetForm();
    });
  }
};
const rowDblClick = (rowdata: T) => {
  const formTitle = props.renderFormTitle('edit', rowdata);
  const id: string = nanoid();

  const menuItem: IMenuItem = {
    id: `menu-item-${id}`,
    menuItemName: formTitle,
    state: { value: 'edit', label: '【编辑】', color: 'green' },
    dataId: rowdata.id,
  };
  menuGroupRef.value.addFormMenu(menuItem);
};
const getSelectionRows = () => {
  return tableRef.value.getSelectionRows();
};
const getSelectionRow = () => {
  return tableRef.value.getSelectionRow();
};
const loadData = () => {
  tableRef.value.loadData();
};
const getFormState = () => {
  const index = menuGroupRef.value.getActiveFormIndex();
  return menuGroupFormRef.value[index].getFormState();
};
defineExpose({ loadData, getSelectionRows, getSelectionRow, getFormState });
</script>
<style lang="scss" scoped>
.dw-data-warpper {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  height: calc(100% - 100px);
}

.required {
  &::before {
    content: '*';
    color: #ff4949;
    margin-right: 2px;
  }
}
</style>
